﻿using System;
using System.Drawing;
using RRRSRoguelike.Entities;
using RRRSRoguelike.Enums;
using RRRSRoguelike.Managers;

namespace RRRSRoguelike.Helpers.Visualizer
{
	/// <summary>
	/// Defines the process for drawing the dungeon level for presentation on the screen.
	/// </summary>
	public class Camera
	{
		#region variables
		int width;
		int height;

		int halfWidth;
		int halfHeight;

		/// <summary>
		/// pushes...erm...something...erm...on the x axis		
		/// </summary>
		public int Xpush;
		/// <summary>
		/// pushes...erm...something...erm...on the y axis	
		/// </summary>
		public int Ypush;

		CameraType type;

		/// <summary>
		/// holds the Camera layer.
		/// </summary>
		public Layer Layer;

		#endregion
		#region constructors
		/// <summary>
		/// HACK: Currently hard coded with a 21X21 max.
		/// </summary>
		/// <param name="width">should be odd and less than 22</param>
		/// <param name="height">should be odd and less than 22</param>
		/// <param name="type">not implemented but will allow diferent shapes</param>
		public Camera(int width, int height, CameraType type = CameraType.Rounded)
		{
			this.width = Math.Min(21, width);
			this.height = Math.Min(21, height);

			//makesure it is odd so can have center.
			if (width % 2 > 0) width++;
			if (height % 2 > 0) height++;
			halfWidth = width / 2;
			halfHeight = height / 2;

			Xpush = (21 - width) / 2;
			Ypush = (21 - height) / 2;

			this.type = type;

			Layer = new Layer(width, height);
		}
		#endregion
		#region properties
		/// <summary>
		/// Height of camera
		/// </summary>
		public int Height
		{ get { return height; } }
		/// <summary>
		/// Height of camera
		/// </summary>
		public int Width
		{ get { return width; } }
		#endregion
		#region methods
		//moved these here to speed up drawing maybe an uneccessary optimisation
		DungeonSquare view;
		Point start;
		DungeonSquare View(Point index, DungeonLevel level, Point focus)
		{
			start = new Point(focus.X - halfWidth, focus.Y - halfHeight);

			GrabDungeonSquare(index, level);

			return view;
		}

		DungeonSquare View(Point index, DungeonLevel level)
		{
			if (Properties.Settings.Default.FollowToggle)
			{
				start = new Point(GameManager.Instance.CreatureManager.Player.X - halfWidth, GameManager.Instance.CreatureManager.Player.Y - halfHeight);
			}
			else
				start = new Point(0, 0);

			GrabDungeonSquare(index, level);

			return view;
		}

		private void GrabDungeonSquare(Point index, DungeonLevel level)
		{
			if (start.X + index.X >= 0 && start.Y + index.Y >= 0 &&
				start.X + index.X <= level.layers[0].GetUpperBound(0) &&
				start.Y + index.Y <= level.layers[0].GetUpperBound(1))
			{
				var tile = (Tile)level.GetTopTile(new Point(start.X + index.X, start.Y + index.Y));
				view.character = tile.ImageCharacter;
				view.color = tile.Color;
				view.background = tile.Background;
				if (tile.Background == ConsoleColor.Magenta)
				{
					for (int i = level.layers.Count - 1; i >= 0; i--)
					{
						if (level.layers[i][index.X, index.Y] != null &&
							   level.layers[i][index.X, index.Y].Background != ConsoleColor.Magenta)
						{
							view.background = level.layers[i][index.X, index.Y].Background;
						}

					}
				}

			}
			else
			{
				view.character = " ";
				view.color = ConsoleColor.Black;
				view.background = ConsoleColor.Black;
			}

			if (type == CameraType.Rounded)
			{
				//Add black tiles to corners or bevel
			}
		}

		/// <summary>
		/// Draws dungeon in view of camera using visualizer.
		/// </summary>
		/// <param name="dungeonLevel"></param>
		/// <param name="StartPoint"></param>
		public void Draw(DungeonLevel dungeonLevel, Point StartPoint)
		{
			for (var i = 0; i < Height; i++)
			{
				for (var j = 0; j < Width; j++)
				{
					//should this be in the camera?
					Layer.DungeonSquares[j, i] = View(new Point(j, i), dungeonLevel);
					if (Layer.HasChanged(j, i))
					{
						Visualizer.WriteLine(Layer.DungeonSquares[j, i],
							new Point(StartPoint.X + Xpush + j, StartPoint.Y + Ypush + i));
						Layer.OldDungeonSquares[j, i] = Layer.DungeonSquares[j, i];
					}
				}
			}
		}
		#endregion
	}
}
